package com.inspur.edp.bef.bizentity.common;

import com.inspur.edp.bef.bizentity.GspBizEntityElement;
import com.inspur.edp.bef.bizentity.GspBizEntityObject;
import com.inspur.edp.bef.bizentity.exceptions.BusinessEntityErrorCodeEnum;
import com.inspur.edp.bef.bizentity.exceptions.BusinessEntityException;
import com.inspur.edp.cef.designtime.api.util.Guid;
import com.inspur.edp.das.commonmodel.entity.object.GspCommonObjectType;
import io.iec.edp.caf.businessobject.api.entity.DevBasicBoInfo;
import io.iec.edp.caf.businessobject.api.service.DevBasicInfoService;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.databaseobject.api.entity.DataType;
import io.iec.edp.caf.databaseobject.api.entity.DatabaseObjectColumn;
import io.iec.edp.caf.databaseobject.api.entity.DatabaseObjectTable;
import io.iec.edp.caf.databaseobject.api.entity.DatabaseObjectTempTable;
import lombok.var;

public class SysnDboUtils {

    //region createDbo
    public static DatabaseObjectTable createDbo(GspBizEntityObject bizObject, String boId, Boolean isUsingTimeStamp){
        DatabaseObjectTable table = generateDboFromBizObject(bizObject, boId, bizObject.getRefObjectName(), isUsingTimeStamp);
        bizObject.setRefObjectName(table.getId());
        return table;
    }



    public static DatabaseObjectTempTable createTempDbo(GspBizEntityObject bizObject){
        DatabaseObjectTempTable table = generateTempDboFromBizObject(bizObject);
        bizObject.setRefObjectName(table.getId());
        return table;
    }

    private static DatabaseObjectTable generateDboFromBizObject(GspBizEntityObject bizObject, String boId, String dboID, Boolean usingTimeStamp) {
        //20180802修改_由于外层已确认设计时/运行时均无此dbo，故仅使用原dboID新建
        String dboCode = getDboNameWithAppCode(bizObject.getCode(), boId);
        String dboName = bizObject.getName();

        //20180817 dbo添加[是否生成时间戳][是否年度表]
        boolean isFiscalTable = false;
        boolean isUsingTimeStamp = getIsUsingTimeStamp(bizObject, usingTimeStamp);

//        //新建dbo时，检查dbo文件名/表名
//        CheckDboFileNameRepeat(path, dboCode);
//        CheckDboTableNameRepeat(path, dboCode);

        DatabaseObjectTable table = new DatabaseObjectTable(dboCode, dboName, false, false, isUsingTimeStamp, isFiscalTable, boId, dboID);

        for (var ele :
                bizObject.getContainElements()) {
            if (ele.getIsVirtual())
                continue;
            addDboColumn((GspBizEntityElement)ele, table, bizObject.getIDElement().getID());
        }
        return table;
    }

    private static DatabaseObjectTempTable generateTempDboFromBizObject(GspBizEntityObject bizObject) {
        //20180802修改_由于外层已确认设计时/运行时均无此dbo，故仅使用原dboID新建
        String dboCode = "temp";
        String dboName = bizObject.getName();

        //20180817 dbo添加[是否生成时间戳][是否年度表]
        boolean isFiscalTable = false;

//        //新建dbo时，检查dbo文件名/表名
//        CheckDboFileNameRepeat(path, dboCode);
//        CheckDboTableNameRepeat(path, dboCode);

        DatabaseObjectTempTable table = new DatabaseObjectTempTable();
        table.setCode(dboCode);
        table.setName(dboName);
        table.setI18nObject(false);
        table.setFiscalTable(false);
        table.setSynHis(false);

        for (var ele :
                bizObject.getContainElements()) {
            if (ele.getIsVirtual())
                continue;
            addDboColumn((GspBizEntityElement)ele, table, bizObject.getIDElement().getID());
        }
        return table;
    }

    public static String getDboNameWithAppCode(String objCode, String boId) {
        DevBasicBoInfo boInfo = SpringBeanUtils.getBean(DevBasicInfoService.class).getDevBasicBoInfo(boId);
        if(boInfo == null) {
            throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_BUSINESS_ENTITY_0066, boId);
        }
        String appCode = boInfo.getAppCode();
        return appCode+objCode;
    }

    public static boolean getIsUsingTimeStamp(GspBizEntityObject bizObject, boolean isUsingTimeStamp)
    {
        if (bizObject.getObjectType() == GspCommonObjectType.MainObject) {
            return isUsingTimeStamp;
        }
        return false;
    }

    //endregion

    //region addBboColumn
    public static void addDboColumn(GspBizEntityElement beElement, DatabaseObjectTable table, String primaryKeyID) {
        String refEleID = Guid.newGuid().toString();
        beElement.setColumnID(refEleID);

        boolean isPrimaryKey = beElement.getID().equals(primaryKeyID);

        var info = getLengthPrecisionScale(beElement);
        //字段唯一则非空
        table.addColumn(
                refEleID,
                beElement.getLabelID(),
                beElement.getName(),
                getDataTypeByMDataType(beElement),
                info.length,
                info.precision,
                info.scale,
                null,
                isPrimaryKey,
                isPrimaryKey,
                !isPrimaryKey,
                beElement.getIsMultiLanguage());

    }

    public static DatabaseObjectColumn addDboColumn(
            GspBizEntityElement beElement,
            DatabaseObjectTable table,
            String primaryKeyID,
            String code,
            String name,
            int length,
            int precision,
            int scale){
        String refEleID = Guid.newGuid().toString();
        beElement.setColumnID(refEleID);
        boolean isPrimaryKey = beElement.getID().equals(primaryKeyID);
        //字段唯一则非空
        table.addColumn(
                refEleID,
                code,
                name,
                getDataTypeByMDataType(beElement),
                length,
                precision,
                scale,
                null,
                isPrimaryKey,
                isPrimaryKey,
                !isPrimaryKey,
                beElement.getIsMultiLanguage());

        return table.getColumnById(refEleID);
    }
    public static DataType getDataTypeByMDataType(GspBizEntityElement ele) {
        var mDataType = ele.getMDataType();

        //多语字段的控制
        if (ele.getIsMultiLanguage()) {
            switch (mDataType) {
                case String:
                    return DataType.NVarchar;
                case Text:
                    return DataType.NClob;
                default:
                    throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_BUSINESS_ENTITY_0067, ele.getName());
            }
        }

        //字段数据类型转换为列数据类型
        switch (mDataType) {
            case Integer:
                return DataType.Int;
            case Decimal:
                return DataType.Decimal;
            case String:
                return DataType.Varchar;
            case Boolean:
                return DataType.Char;
            case Text:
                return DataType.Clob;
            case Date:
                return DataType.DateTime;
            case DateTime:
                return DataType.TimeStamp;
            case Binary:
                return DataType.Blob;
            default:
                throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_BUSINESS_ENTITY_0039, mDataType.toString());
        }
    }

    private static ElementLengthInfo getLengthPrecisionScale(GspBizEntityElement element) {
        int length = 0;
        int precision = 0;
        int scale = 0;

        // 解决lcm的长度精度小数位数与beElementDataType中长度精度小数位数中表达不一致问题
        switch (element.getMDataType()) {
            //整型，赋值长度
            case Integer:
                length = 0;
                precision = 0;
                scale = 0;
                break;
            //字符串，赋值长度
            case String:
                length = element.getLength();
                precision = 0;
                scale = 0;
                break;
            //浮点数字，赋值精度，小数位数
            case Decimal:
                length = 0;
                precision = element.getLength();
                scale = element.getPrecision();
                break;
            //布尔型
            case Boolean:
                length = 1;
                precision = 0;
                scale = 0;
                break;
            //其他，0,0,0
        }

        return new ElementLengthInfo(length, precision, scale);
    }

    static class ElementLengthInfo {
        private int length;
        private int precision;
        private int scale;

        ElementLengthInfo(int length, int precision, int scale) {
            this.length = length;
            this.precision = precision;
            this.scale = scale;
        }
    }
    //endregion
}
